<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Element Reflection for aria-activedescendant and aria-errormessage on ElementInternals</title>
  <link rel=help href="https://whatpr.org/html/3917/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:element">
  <link rel="author" title="Alice Boxhall" href="alice@igalia.com">
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
</head>

<body>
  <script>
    class CustomElement extends HTMLElement {
      constructor() {
        super();
        this.i = this.attachInternals();
      }
    }
    customElements.define('custom-element', CustomElement);
  </script>

  <custom-element id="custom1"></custom-element>
  <div id="activedescendant">Active descendant</div>
  <div id="controls">Controls</div>
  <div id="describedby">Described by</div>
  <div id="details">Details</div>
  <div id="errormessage">Error message</div>
  <div id="flowto">Flow to</div>
  <div id="labelledby">Labelled By</div>
  <div id="owns">Owns</div>

  <script>
    const element_properties = [
      ['ariaActiveDescendantElement', 'activedescendant']];
    const array_properties = [
      ['ariaControlsElements', 'controls'],
      ['ariaDescribedByElements', 'describedby'],
      ['ariaDetailsElements', 'details'],
      ['ariaErrorMessageElements', 'errormessage'],
      ['ariaFlowToElements', 'flowto'],
      ['ariaLabelledByElements', 'labelledby'],
      ['ariaOwnsElements', 'owns']];

    test(t => {
      const custom = document.getElementById('custom1');
      for (const [property, id] of element_properties) {
        assert_equals(custom.i[property], null);
      }
      for (const [property, id] of array_properties) {
        assert_equals(custom.i[property], null);
      }
    }, "Getting previously-unset ARIA element reflection properties on ElementInternals should return null.");

    test(t => {
      const custom = document.getElementById('custom1');
      for (const [property, id] of element_properties) {
        const related = document.getElementById(id);
        custom.i[property] = related;
        assert_equals(custom.i[property], related);
      }
      for (const [property, id] of array_properties) {
        const related = document.getElementById(id);
        custom.i[property] = [related];
        assert_array_equals(custom.i[property], [related]);
      }
    }, "Getting ARIA element reflection properties on ElementInternals should return the value that was set.");

    test(t => {
      const custom = document.getElementById('custom1');
      for (const [property, id] of array_properties) {
        custom.i[property] = [];
        assert_array_equals(custom.i[property], []);
      }
    }, "Setting ARIA element reflection properties to an empty array should work as expected.");

    test(t => {
      const custom = document.getElementById('custom1');
      for (const [property, id] of element_properties) {
        const related = document.getElementById(id);
        custom.i[property] = related;
        assert_equals(custom.i[property], related);

        custom.i[property] = null;
        assert_equals(custom.i[property], null);
      }
      for (const [property, id] of array_properties) {
        const related = document.getElementById(id);
        custom.i[property] = [related];
        assert_array_equals(custom.i[property], [related]);

        custom.i[property] = null;
        assert_equals(custom.i[property], null);
      }
    }, "Setting ARIA element reflection properties on ElementInternals to null should delete any previous value, and not crash");
  </script>

  <custom-element id="cachingInvariantMain"></custom-element>
  <div id="cachingInvariantElement1"></div>
  <div id="cachingInvariantElement2"></div>
  <div id="cachingInvariantElement3"></div>
  <div id="cachingInvariantElement4"></div>
  <div id="cachingInvariantElement5"></div>

  <script>
    test(function(t) {
      cachingInvariantMain.i.ariaControlsElements = [cachingInvariantElement1, cachingInvariantElement2];
      cachingInvariantMain.i.ariaDescribedByElements = [cachingInvariantElement3, cachingInvariantElement4];
      cachingInvariantMain.i.ariaDetailsElements = [cachingInvariantElement5];
      cachingInvariantMain.i.ariaFlowToElements = [cachingInvariantElement1, cachingInvariantElement3];
      cachingInvariantMain.i.ariaLabelledByElements = [cachingInvariantElement2, cachingInvariantElement4];
      cachingInvariantMain.i.ariaOwnsElements = [cachingInvariantElement1, cachingInvariantElement2, cachingInvariantElement3];

      let ariaControlsElementsArray = cachingInvariantMain.i.ariaControlsElements;
      let ariaDescribedByElementsArray = cachingInvariantMain.i.ariaDescribedByElements;
      let ariaDetailsElementsArray = cachingInvariantMain.i.ariaDetailsElements;
      let ariaFlowToElementsArray = cachingInvariantMain.i.ariaFlowToElements;
      let ariaLabelledByElementsArray = cachingInvariantMain.i.ariaLabelledByElements;
      let ariaOwnsElementsArray = cachingInvariantMain.i.ariaOwnsElements;

      assert_equals(ariaControlsElementsArray, cachingInvariantMain.i.ariaControlsElements, "Caching invariant for ariaControlsElements");
      assert_equals(ariaDescribedByElementsArray, cachingInvariantMain.i.ariaDescribedByElements, "Caching invariant for ariaDescribedByElements");
      assert_equals(ariaDetailsElementsArray, cachingInvariantMain.i.ariaDetailsElements, "Caching invariant for ariaDetailsElements");
      assert_equals(ariaFlowToElementsArray, cachingInvariantMain.i.ariaFlowToElements, "Caching invariant for ariaFlowToElements");
      assert_equals(ariaLabelledByElementsArray, cachingInvariantMain.i.ariaLabelledByElements, "Caching invariant for ariaLabelledByElements");
      assert_equals(ariaOwnsElementsArray, cachingInvariantMain.i.ariaOwnsElements, "Caching invariant for ariaOwnsElements");

      // Ensure that cached values don't become stale
      cachingInvariantMain.i.ariaControlsElements = [cachingInvariantElement4, cachingInvariantElement5];
      cachingInvariantMain.i.ariaDescribedByElements = [cachingInvariantElement1, cachingInvariantElement2];
      cachingInvariantMain.i.ariaDetailsElements = [cachingInvariantElement3];
      cachingInvariantMain.i.ariaFlowToElements = [cachingInvariantElement4, cachingInvariantElement5];
      cachingInvariantMain.i.ariaLabelledByElements = [cachingInvariantElement1, cachingInvariantElement2];
      cachingInvariantMain.i.ariaOwnsElements = [cachingInvariantElement3, cachingInvariantElement4, cachingInvariantElement1];

      ariaControlsElementsArray = cachingInvariantMain.i.ariaControlsElements;
      ariaDescribedByElementsArray = cachingInvariantMain.i.ariaDescribedByElements;
      ariaDetailsElementsArray = cachingInvariantMain.i.ariaDetailsElements;
      ariaFlowToElementsArray = cachingInvariantMain.i.ariaFlowToElements;
      ariaLabelledByElementsArray = cachingInvariantMain.i.ariaLabelledByElements;
      ariaOwnsElementsArray = cachingInvariantMain.i.ariaOwnsElements;

      assert_equals(ariaControlsElementsArray, cachingInvariantMain.i.ariaControlsElements, "Caching invariant for ariaControlsElements");
      assert_equals(ariaDescribedByElementsArray, cachingInvariantMain.i.ariaDescribedByElements, "Caching invariant for ariaDescribedByElements");
      assert_equals(ariaDetailsElementsArray, cachingInvariantMain.i.ariaDetailsElements, "Caching invariant for ariaDetailsElements");
      assert_equals(ariaFlowToElementsArray, cachingInvariantMain.i.ariaFlowToElements, "Caching invariant for ariaFlowToElements");
      assert_equals(ariaLabelledByElementsArray, cachingInvariantMain.i.ariaLabelledByElements, "Caching invariant for ariaLabelledByElements");
      assert_equals(ariaOwnsElementsArray, cachingInvariantMain.i.ariaOwnsElements, "Caching invariant for ariaOwnsElements");

    }, "Caching invariant different attributes.");
  </script>

  <custom-element id="cachingInvariantMain1"></custom-element>
  <custom-element id="cachingInvariantMain2"></custom-element>

  <script>
    test(function(t) {
      cachingInvariantMain1.i.ariaDescribedByElements = [cachingInvariantElement1, cachingInvariantElement2];
      cachingInvariantMain2.i.ariaDescribedByElements = [cachingInvariantElement1, cachingInvariantElement2];

      let ariaDescribedByElementsArray1 = cachingInvariantMain1.i.ariaDescribedByElements;
      let ariaDescribedByElementsArray2 = cachingInvariantMain2.i.ariaDescribedByElements;

      assert_equals(ariaDescribedByElementsArray1, cachingInvariantMain1.i.ariaDescribedByElements, "Caching invariant for ariaDescribedByElements in one elemnt");
      assert_equals(ariaDescribedByElementsArray2, cachingInvariantMain2.i.ariaDescribedByElements, "Caching invariant for ariaDescribedByElements in onother elemnt");
      assert_not_equals(cachingInvariantMain1.i.ariaDescribedByElements, cachingInvariantMain2.i.ariaDescribedByElements);
    }, "Caching invariant different elements.");
  </script>

  </script>
</body>
</html>